#include "pp_tags.h"
#include "pp_utils.h"

namespace pp
{
    TagParser::TagParser() : m_u32Pos(0)
    {
        m_fnState = &TagParser::OnTagStateInit;
    }

    void TagParser::Reset()
    {
        m_u32Pos = 0;
        m_sName = "";
        m_fnState = &TagParser::OnTagStateInit;
        m_oTags.clear();
    }

    // 解析字符串
    void TagParser::Parse(const std::string& data, std::map<std::string, std::string>& attrs)
    {
        if (data.empty()) return;

        uint32_t len = data.length();
        const char* bytes = data.data();

        Reset();

        for (uint32_t i = 0; i < len; i++)
        {
            (this->*m_fnState)(i, bytes[i], data);
        }

        ParseTags(attrs);
    }

    void TagParser::OnTagStateInit(uint32_t pos, char ch, const std::string& data)
    {
        if (ch == ':')
        {
            m_sName = Trim(data.substr(m_u32Pos, pos - m_u32Pos));
            m_fnState = &TagParser::OnTagStateValue;
        }
    }

    void TagParser::OnTagStateValue(uint32_t pos, char ch, const std::string& data)
    {
        if (ch == '\"')
        {
            m_u32Pos = pos + 1;
            m_fnState = &TagParser::OnTagStateValueEnd;
        }
    }

    void TagParser::OnTagStateValueEnd(uint32_t pos, char ch, const std::string& data)
    {
        if (ch == '\"')
        {
            if (!m_sName.empty())
            {
                m_oTags[m_sName] = Trim(data.substr(m_u32Pos, pos - m_u32Pos));
            }
            m_u32Pos = pos + 1;
            m_fnState = &TagParser::OnTagStateInit;
        }
    }

    void TagParser::ParseTags(std::map<std::string, std::string>& attrs)
    {
        std::map<std::string, std::string>::iterator iter;

        for (iter = m_oTags.begin(); iter != m_oTags.end(); iter++)
        {
            if (iter->first == "json")
            {
                // json:"email,omitempty"
                ParseJsonTags(iter->second, attrs);
            }
            else if (iter->first == "pp")
            {
                // pp:"default:45;size:200"
                ParsePPTags(iter->second, attrs);
            }
        }
    }

    void TagParser::ParseJsonTags(const std::string& s, std::map<std::string, std::string>& attrs)
    {
        std::vector<std::string> vals;
        Split(s, ",", vals);

        std::vector<std::string>::iterator iter;
        for (iter = vals.begin(); iter != vals.end(); iter++)
        {
            std::string val = Trim(*iter);

            if (val == "omitempty")
            {
                attrs["json_omitempty"] = "omitempty";
            }
            else
            {
                attrs["json_name"] = val;
            }
        }
    }

    void TagParser::ParsePPTags(const std::string& s, std::map<std::string, std::string>& attrs)
    {
        std::vector<std::string> vals;
        Split(s, ";", vals);

        std::vector<std::string>::iterator iter;
        for (iter = vals.begin(); iter != vals.end(); iter++)
        {
            std::vector<std::string> vvals;
            Split(*iter, ":", vvals);

            if (vvals.size() != 2) continue;

            attrs[Trim(vvals[0])] = Trim(vvals[1]);
        }
    }
};
